package dao

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"sort"
	"time"
	"user_srv/basic/config"
	"user_srv/handler/models"
)

// SoulQuestionDAO 灵魂测试题目相关操作
type SoulQuestionDAO struct{}

// GetQuestionsByCategory 根据分类获取题目
func (sqd *SoulQuestionDAO) GetQuestionsByCategory(categoryId uint64, limit int) ([]models.SoulQuestion, error) {
	var questions []models.SoulQuestion

	query := config.DB.Where("category_id = ? AND is_active = 1", categoryId)
	if limit > 0 {
		query = query.Limit(limit)
	}

	err := query.Order("sort_order ASC").Find(&questions).Error
	return questions, err
}

// GetRandomQuestions 获取随机题目
func (sqd *SoulQuestionDAO) GetRandomQuestions(limit int) ([]models.SoulQuestion, error) {
	var questions []models.SoulQuestion

	err := config.DB.Where("is_active = 1").
		Order("RAND()").
		Limit(limit).
		Find(&questions).Error

	return questions, err
}

// GetQuestionById 根据ID获取题目
func (sqd *SoulQuestionDAO) GetQuestionById(questionId uint64) (*models.SoulQuestion, error) {
	var question models.SoulQuestion
	err := config.DB.Where("id = ? AND is_active = 1", questionId).First(&question).Error
	if err != nil {
		return nil, err
	}
	return &question, nil
}

// SoulAnswerDAO 用户答题相关操作
type SoulAnswerDAO struct{}

// SaveAnswer 保存用户答案
func (sad *SoulAnswerDAO) SaveAnswer(userId, questionId uint64, answerContent string, answerScore float64) error {
	// 检查是否已经回答过
	var existingAnswer models.SoulAnswer
	err := config.DB.Where("user_id = ? AND question_id = ?", userId, questionId).First(&existingAnswer).Error

	if err == nil {
		// 更新现有答案
		existingAnswer.AnswerContent = answerContent
		existingAnswer.AnswerScore = answerScore
		existingAnswer.AnsweredAt = time.Now()
		return existingAnswer.Update()
	}

	// 创建新答案
	answer := models.SoulAnswer{
		UserId:        userId,
		QuestionId:    questionId,
		AnswerContent: answerContent,
		AnswerScore:   answerScore,
		AnsweredAt:    time.Now(),
	}

	return answer.Create()
}

// GetUserAnswers 获取用户所有答案
func (sad *SoulAnswerDAO) GetUserAnswers(userId uint64) ([]models.SoulAnswer, error) {
	var answer models.SoulAnswer
	return answer.GetByUserId(userId)
}

// GetUserAnswerByQuestion 获取用户对特定题目的答案
func (sad *SoulAnswerDAO) GetUserAnswerByQuestion(userId, questionId uint64) (*models.SoulAnswer, error) {
	var answer models.SoulAnswer
	err := answer.GetByUserAndQuestion(userId, questionId)
	if err != nil {
		return nil, err
	}
	return &answer, nil
}

// SoulTestResultDAO 测试结果相关操作
type SoulTestResultDAO struct{}

// SaveTestResult 保存测试结果
func (strd *SoulTestResultDAO) SaveTestResult(userId uint64, testVersion string, totalScore float64,
	dimensionScores, personalityType, matchPreferences string, testDuration int) error {

	// 检查是否已有测试结果
	var existingResult models.SoulTestResult
	err := config.DB.Where("user_id = ?", userId).First(&existingResult).Error

	if err == nil {
		// 更新现有结果
		existingResult.TestVersion = testVersion
		existingResult.TotalScore = totalScore
		existingResult.DimensionScores = dimensionScores
		existingResult.PersonalityType = personalityType
		existingResult.MatchPreferences = matchPreferences
		existingResult.TestDuration = testDuration
		existingResult.CompletedAt = time.Now()
		return existingResult.Update()
	}

	// 创建新结果
	result := models.SoulTestResult{
		UserId:           userId,
		TestVersion:      testVersion,
		TotalScore:       totalScore,
		DimensionScores:  dimensionScores,
		PersonalityType:  personalityType,
		MatchPreferences: matchPreferences,
		TestDuration:     testDuration,
		CompletedAt:      time.Now(),
	}

	return result.Create()
}

// GetUserTestResult 获取用户测试结果
func (strd *SoulTestResultDAO) GetUserTestResult(userId uint64) (*models.SoulTestResult, error) {
	var result models.SoulTestResult
	err := result.GetByUserId(userId)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// SoulMatchDAO 灵魂匹配相关操作
type SoulMatchDAO struct{}

// CalculateSoulMatchScore 计算灵魂匹配分数
func (smd *SoulMatchDAO) CalculateSoulMatchScore(user1Id, user2Id uint64) (float64, string, error) {
	// 获取两个用户的测试结果
	result1, err := (&SoulTestResultDAO{}).GetUserTestResult(user1Id)
	if err != nil || result1 == nil {
		return 0, "", errors.New("用户1未完成灵魂测试")
	}

	result2, err := (&SoulTestResultDAO{}).GetUserTestResult(user2Id)
	if err != nil || result2 == nil {
		return 0, "", errors.New("用户2未完成灵魂测试")
	}

	// 解析维度分数
	var scores1, scores2 map[string]float64
	err = json.Unmarshal([]byte(result1.DimensionScores), &scores1)
	if err != nil {
		return 0, "", errors.New("解析用户1维度分数失败")
	}

	err = json.Unmarshal([]byte(result2.DimensionScores), &scores2)
	if err != nil {
		return 0, "", errors.New("解析用户2维度分数失败")
	}

	// 计算匹配分数
	totalScore := 0.0
	matchReasons := []string{}
	dimensionScores := make(map[string]float64)

	// 获取所有维度
	dimensions, err := (&SoulPersonalityDimensionDAO{}).GetAllDimensions()
	if err != nil {
		return 0, "", err
	}

	// 计算各维度匹配分数
	for _, dimension := range dimensions {
		score1, exists1 := scores1[dimension.DimensionCode]
		score2, exists2 := scores2[dimension.DimensionCode]

		if !exists1 || !exists2 {
			continue
		}

		// 使用改进的匹配算法
		dimensionScore := smd.calculateDimensionMatchScore(score1, score2, dimension.DimensionCode)
		dimensionScores[dimension.DimensionCode] = dimensionScore
		totalScore += dimensionScore * dimension.Weight

		// 生成匹配原因
		if dimensionScore > 0.85 {
			matchReasons = append(matchReasons, fmt.Sprintf("%s高度契合", dimension.DimensionName))
		} else if dimensionScore > 0.7 {
			matchReasons = append(matchReasons, fmt.Sprintf("%s较为契合", dimension.DimensionName))
		} else if dimensionScore > 0.5 {
			matchReasons = append(matchReasons, fmt.Sprintf("%s基本匹配", dimension.DimensionName))
		}
	}

	// 计算最终分数
	finalScore := 0.0
	if len(dimensions) > 0 {
		finalScore = totalScore / float64(len(dimensions)) * 100
	}

	// 添加互补性匹配加分
	complementaryBonus := smd.calculateComplementaryBonus(scores1, scores2)
	finalScore += complementaryBonus

	// 确保分数在合理范围内
	if finalScore > 100 {
		finalScore = 100
	}
	if finalScore < 0 {
		finalScore = 0
	}

	// 序列化匹配原因
	reasonsJson, _ := json.Marshal(matchReasons)

	return finalScore, string(reasonsJson), nil
}

// calculateDimensionMatchScore 计算单个维度的匹配分数
func (smd *SoulMatchDAO) calculateDimensionMatchScore(score1, score2 float64, dimensionCode string) float64 {
	// 基础相似性计算
	similarity := 1.0 - math.Abs(score1-score2)/10.0

	// 根据维度类型调整匹配策略
	switch dimensionCode {
	case "EXTROVERSION", "INTROVERSION":
		// 外向性/内向性：相似性匹配
		return similarity
	case "SENSING", "INTUITION":
		// 感觉型/直觉型：互补性匹配
		return smd.calculateComplementaryMatch(score1, score2)
	case "THINKING", "FEELING":
		// 思考型/情感型：互补性匹配
		return smd.calculateComplementaryMatch(score1, score2)
	case "JUDGING", "PERCEIVING":
		// 判断型/感知型：相似性匹配
		return similarity
	default:
		// 默认使用相似性匹配
		return similarity
	}
}

// calculateComplementaryMatch 计算互补性匹配分数
func (smd *SoulMatchDAO) calculateComplementaryMatch(score1, score2 float64) float64 {
	// 互补性匹配：差异越大，匹配度越高（但有限制）
	difference := math.Abs(score1 - score2)

	// 使用反比例函数，差异在3-7之间时匹配度最高
	if difference >= 3 && difference <= 7 {
		return 0.8 + (difference-3)*0.05 // 0.8-0.95
	} else if difference < 3 {
		return 0.6 + difference*0.1 // 0.6-0.8
	} else {
		return 0.9 - (difference-7)*0.1 // 0.9-0.7
	}
}

// calculateComplementaryBonus 计算互补性加分
func (smd *SoulMatchDAO) calculateComplementaryBonus(scores1, scores2 map[string]float64) float64 {
	bonus := 0.0

	// 检查关键维度的互补性
	complementaryPairs := [][]string{
		{"SENSING", "INTUITION"},
		{"THINKING", "FEELING"},
	}

	for _, pair := range complementaryPairs {
		score1A, exists1A := scores1[pair[0]]
		score1B, exists1B := scores1[pair[1]]
		score2A, exists2A := scores2[pair[0]]
		score2B, exists2B := scores2[pair[1]]

		if exists1A && exists1B && exists2A && exists2B {
			// 检查是否形成互补
			if (score1A > score1B && score2A < score2B) || (score1A < score1B && score2A > score2B) {
				bonus += 5.0 // 互补性加分
			}
		}
	}

	return bonus
}

// CreateSoulMatchRecord 创建灵魂匹配记录
func (smd *SoulMatchDAO) CreateSoulMatchRecord(user1Id, user2Id uint64, matchScore float64,
	matchReasons, dimensionScores string) error {

	// 检查是否已存在匹配记录
	var existingRecord models.SoulMatchRecord
	err := existingRecord.GetByUserPair(user1Id, user2Id)
	if err == nil {
		// 更新现有记录
		existingRecord.MatchScore = matchScore
		existingRecord.MatchReasons = matchReasons
		existingRecord.DimensionScores = dimensionScores
		existingRecord.Status = 1
		return existingRecord.Update()
	}

	// 创建新记录
	record := models.SoulMatchRecord{
		User1Id:         user1Id,
		User2Id:         user2Id,
		MatchScore:      matchScore,
		MatchReasons:    matchReasons,
		DimensionScores: dimensionScores,
		MatchType:       1, // 系统推荐
		Status:          1, // 有效
	}

	return record.Create()
}

// GetSoulMatches 获取用户的灵魂匹配列表
func (smd *SoulMatchDAO) GetSoulMatches(userId uint64, limit int) ([]models.SoulMatchRecord, error) {
	var record models.SoulMatchRecord
	records, err := record.GetByUserId(userId)
	if err != nil {
		return nil, err
	}

	// 限制返回数量
	if limit > 0 && len(records) > limit {
		records = records[:limit]
	}

	return records, nil
}

// GetSoulMatchCandidates 获取灵魂匹配候选用户
func (smd *SoulMatchDAO) GetSoulMatchCandidates(userId uint64, limit int) ([]models.User, error) {
	// 获取用户测试结果
	_, err := (&SoulTestResultDAO{}).GetUserTestResult(userId)
	if err != nil {
		return nil, errors.New("用户未完成灵魂测试")
	}

	// 获取所有完成测试的用户
	var candidates []models.User
	err = config.DB.Raw(`
		SELECT u.* FROM user u 
		INNER JOIN soul_test_result str ON u.id = str.user_id 
		WHERE u.id != ? AND u.status = 1 
		ORDER BY str.total_score DESC 
		LIMIT ?
	`, userId, limit*3).Scan(&candidates).Error

	if err != nil {
		return nil, err
	}

	// 计算匹配分数并排序
	type CandidateWithScore struct {
		User  models.User
		Score float64
	}

	var candidatesWithScore []CandidateWithScore
	for _, candidate := range candidates {
		score, _, err := smd.CalculateSoulMatchScore(userId, candidate.Id)
		if err != nil {
			continue
		}

		candidatesWithScore = append(candidatesWithScore, CandidateWithScore{
			User:  candidate,
			Score: score,
		})
	}

	// 按分数排序
	sort.Slice(candidatesWithScore, func(i, j int) bool {
		return candidatesWithScore[i].Score > candidatesWithScore[j].Score
	})

	// 限制返回数量
	if len(candidatesWithScore) > limit {
		candidatesWithScore = candidatesWithScore[:limit]
	}

	// 提取用户列表
	var result []models.User
	for _, item := range candidatesWithScore {
		result = append(result, item.User)
	}

	return result, nil
}

// SoulPersonalityDimensionDAO 性格维度相关操作
type SoulPersonalityDimensionDAO struct{}

// GetAllDimensions 获取所有性格维度
func (spdd *SoulPersonalityDimensionDAO) GetAllDimensions() ([]models.SoulPersonalityDimension, error) {
	var dimension models.SoulPersonalityDimension
	return dimension.GetAll()
}

// CreateDimension 创建性格维度
func (spdd *SoulPersonalityDimensionDAO) CreateDimension(name, code, description string, weight float64) error {
	dimension := models.SoulPersonalityDimension{
		DimensionName: name,
		DimensionCode: code,
		Description:   description,
		Weight:        weight,
		IsActive:      1,
	}

	return dimension.Create()
}

// SoulUserDimensionScoreDAO 用户维度分数相关操作
type SoulUserDimensionScoreDAO struct{}

// SaveUserDimensionScores 保存用户维度分数
func (sudsd *SoulUserDimensionScoreDAO) SaveUserDimensionScores(userId uint64, scores map[string]float64) error {
	// 获取所有维度
	dimensions, err := (&SoulPersonalityDimensionDAO{}).GetAllDimensions()
	if err != nil {
		return err
	}

	// 计算百分位数
	percentiles := make(map[string]float64)
	for _, dimension := range dimensions {
		score, exists := scores[dimension.DimensionCode]
		if !exists {
			continue
		}

		// 计算该维度下所有用户的分数分布
		var count int64
		var higherCount int64

		config.DB.Model(&models.SoulUserDimensionScore{}).
			Where("dimension_id = ?", dimension.Id).
			Count(&count)

		config.DB.Model(&models.SoulUserDimensionScore{}).
			Where("dimension_id = ? AND score > ?", dimension.Id, score).
			Count(&higherCount)

		percentile := float64(higherCount) / float64(count) * 100
		percentiles[dimension.DimensionCode] = percentile
	}

	// 保存或更新用户维度分数
	for _, dimension := range dimensions {
		score, exists := scores[dimension.DimensionCode]
		if !exists {
			continue
		}

		percentile := percentiles[dimension.DimensionCode]

		// 检查是否已存在
		var existingScore models.SoulUserDimensionScore
		err := config.DB.Where("user_id = ? AND dimension_id = ?", userId, dimension.Id).First(&existingScore).Error

		if err == nil {
			// 更新现有分数
			existingScore.Score = score
			existingScore.Percentile = percentile
			existingScore.UpdatedAt = time.Now()
			err = existingScore.Update()
		} else {
			// 创建新分数
			newScore := models.SoulUserDimensionScore{
				UserId:      userId,
				DimensionId: dimension.Id,
				Score:       score,
				Percentile:  percentile,
			}
			err = newScore.Create()
		}

		if err != nil {
			return err
		}
	}

	return nil
}

// GetUserDimensionScores 获取用户维度分数
func (sudsd *SoulUserDimensionScoreDAO) GetUserDimensionScores(userId uint64) ([]models.SoulUserDimensionScore, error) {
	var score models.SoulUserDimensionScore
	return score.GetByUserId(userId)
}
